home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 25
/
Cream of the Crop 25.iso
/
faq
/
wdj0597.zip
/
TECHTIPS.ZIP
/
MASHLAN.ZIP
/
BT.TXT
< prev
Wrap
Text File
|
1997-01-31
|
5KB
|
119 lines
The problem with _beginthread
When you develop a multi-threaded application using the Win32
API, you normally need to use your compiler's run time library
function called _beginthread, rather than the Win32 API function
CreateThread. This is because the run-time library needs to do
per-thread initialization and cleanup, which it can't do if you
use the CreateThread API directly. For instance, if your program
uses C++ exceptions, the run-time library needs to initialize the
exception handling mechanism for that thread. Also, the run-time
library uses global variables like internally for functions like
strtok, so the run-time library must allocate and initialize a
copy of these variables for each thread that uses the RTL.
Both CreateThread and _beginthread return a handle to a thread.
The handle is a magic cookie for an operating system object that
represents the thread. This handle can be used to check the
status of the thread, or it can be used to wait for a thread to
complete if you use one of the WaitForXXX API functions. When
you get the the handle from CreateThread, you are responsible for
closing the handle using CloseHandle function. If you don't
close the handle when you don't need it anymore, you have used up
part of the operating system's resources which are not going to
be released until your application terminates.
One of the things that _beginthread does for you is that it
closes the handle returned by CreateThread when the thread
terminates, either by returning from the thread function or
calling _endthread. This relieves you of the responsibility of
closing that thread handle. However, the problem with the handle
returned by _beginthread is that it is possible that it becomes
invalid before you use it, because the thread started running
then terminated. If you are lucky, the WaitForXXX might return
an ERROR_INVALID_HANDLE, but sometimes the result is a hang.
If you need a valid thread handle from _beginthread, there is a
workaround. In the Borland C++ run-time library, there is a
function called _beginthreadNT, and in the Visual C++ run-time
library there is a function called _beginthreadex which have
parameters additional to what _beginthread uses. One of these
parameters is the creation flag that is passed to CreateThread.
This flag can be CREATE_SUSPENDED, which causes the thread not to
run until you call the ResumeThread function.
Once you create a the thread in a suspended state, you can use
the DuplicateHandle function which creates handle that represents
the same object as the original handle. Once you have duplicated
the handle, you can then allow the thread to run by calling
ResumeThread. This needs to be done while the thread is in a
suspended state because you don't want the thread to run and
possibly terminate before you get a chance to duplicate the
original handle. The handle returned by DuplicateHandle will be
valid until you close it with CloseHandle.
Listing 1 (bt.c) is the source code to a Win32 console mode application
that demonstrates this technique.
// listing 1 bt.c
// note - make sure the multi-threaded library option
// is on in your compiler's IDE settings.
#include <windows.h>
#include <process.h>
#include <stdio.h>
HANDLE beginthread_handle(
#ifdef __BORLANDC__
void _USERENTRY (*start_address)(void *),
#else
unsigned (__stdcall *start_address)(void *),
#endif
unsigned stack_size,
void *arglist )
{
DWORD id;
HANDLE h1 = (HANDLE)
#ifdef __BORLANDC__
_beginthreadNT(start_address,stack_size,
arglist,NULL,CREATE_SUSPENDED,&id);
#else
// for Visual C++ and compatibles
_beginthreadex(NULL,stack_size,start_address,
arglist,CREATE_SUSPENDED,&id);
#endif
HANDLE h2 = INVALID_HANDLE_VALUE;
if( h1 != INVALID_HANDLE_VALUE ) {
DuplicateHandle(GetCurrentProcess(),h1,
GetCurrentProcess(),&h2,0,FALSE,
DUPLICATE_SAME_ACCESS);
ResumeThread(h1);
}
return h2;
}
#ifdef __BORLANDC__
void thread( void *arg )
#else
unsigned __stdcall thread( void * arg )
#endif
{
printf("new thread called\n");
#ifndef __BORLANDC__
return 0;
#endif
}
int main(void)
{
HANDLE h = beginthread_handle(thread,4096,NULL);
if(h!=INVALID_HANDLE_VALUE) {
printf("waiting on new thread\n");
WaitForSingleObject(h,INFINITE);
printf("new thread is signaled\n");
CloseHandle(h);
}
return 0;
}